package org.sam.swing.table.editor;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ItemEvent;
import java.util.Collection;
import java.util.EventObject;

import javax.swing.AbstractCellEditor;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.JTree;
import javax.swing.table.TableCellEditor;
import javax.swing.tree.TreeCellEditor;

/**
 * 集合对象的多行编辑功能控件(基础类型版)
 * 
 * @author sam
 *
 */
public class JSTableCollectionDialogEditor<T> extends AbstractCellEditor implements TableCellEditor, TreeCellEditor {

	private static final long serialVersionUID = -5911992610004327203L;

	/** The Swing component being edited. */
	protected JComponent editorComponent;

	/**
	 * The delegate class which handles all methods sent from the
	 * <code>CellEditor</code>.
	 */
	protected JSEditorDelegateAdapter delegate;

	/**
	 * 设置操作代理对象
	 * 
	 * @return
	 */
	public JSEditorDelegateAdapter getDelegate() {
		return delegate;
	}

	public void setDelegate(JSEditorDelegateAdapter delegate) {

		if (this.delegate != null)
			btn.removeActionListener(this.delegate);

		this.delegate = delegate;

		if (this.delegate != null)
			btn.addActionListener(this.delegate);
	}

	/**
	 * An integer specifying the number of clicks needed to start editing. Even if
	 * <code>clickCountToStart</code> is defined as zero, it will not initiate until
	 * a click occurs.
	 */
	protected int clickCountToStart = 1;

	private JLabel label;

	/**
	 * 主体的框架
	 */
	private JPanel panel;

	/**
	 * 按钮
	 */
	private JButton btn;
	
	/**
	 * 双击编辑弹出集合编辑对话框
	 */
	public JSTableCollectionDialogEditor() {
		this(null,null);
	}
	
	/**
	 * 双击编辑弹出集合编辑对话框
	 * @param defaultValue
	 */
	public JSTableCollectionDialogEditor(T defaultValue) {
		this(null,defaultValue);
	}

	/**
	 * 双击编辑弹出集合编辑对话框
	 * 
	 * @param delegate
	 */
	public JSTableCollectionDialogEditor(JSEditorDelegateAdapter delegate) {
		this(delegate,null);
	}
	
	/**
	 * 双击编辑弹出集合编辑对话框
	 * 
	 * @param delegate
	 * @param defaultValue 默认值
	 */
	public JSTableCollectionDialogEditor(JSEditorDelegateAdapter delegate , T defaultValue) {
		super();
		label = new JLabel();
		btn = new JButton(".");
		panel = new JPanel(new BorderLayout());
		panel.add(label, BorderLayout.CENTER);
		panel.add(btn, BorderLayout.EAST);
		this.editorComponent = panel;
		btn.setVisible(false);

		if (delegate != null) {
			this.setDelegate(delegate);
		} else {
			delegate = new EditorDelegate(defaultValue);
			this.setDelegate(delegate);
		}
		btn.addActionListener(delegate);
		this.clickCountToStart = 2;
	}

	/**
	 * Specifies the number of clicks needed to start editing.
	 *
	 * @param count an int specifying the number of clicks needed to start editing
	 * @see #getClickCountToStart
	 */
	public void setClickCountToStart(int count) {
		clickCountToStart = count;
	}

	/**
	 * Returns the number of clicks needed to start editing.
	 * 
	 * @return the number of clicks needed to start editing
	 */
	public int getClickCountToStart() {
		return clickCountToStart;
	}

	//
	// Override the implementations of the superclass, forwarding all methods
	// from the CellEditor interface to our delegate.
	//

	/**
	 * Forwards the message from the <code>CellEditor</code> to the
	 * <code>delegate</code>.
	 * 
	 * @see EditorDelegate#getCellEditorValue
	 */
	public Object getCellEditorValue() {
		return delegate.getCellEditorValue();
	}

	/**
	 * Forwards the message from the <code>CellEditor</code> to the
	 * <code>delegate</code>.
	 * 
	 * @see EditorDelegate#isCellEditable(EventObject)
	 */
	public boolean isCellEditable(EventObject anEvent) {
		return delegate.isCellEditable(anEvent);
	}

	/**
	 * Forwards the message from the <code>CellEditor</code> to the
	 * <code>delegate</code>.
	 * 
	 * @see EditorDelegate#shouldSelectCell(EventObject)
	 */
	public boolean shouldSelectCell(EventObject anEvent) {
		return delegate.shouldSelectCell(anEvent);
	}

	/**
	 * Forwards the message from the <code>CellEditor</code> to the
	 * <code>delegate</code>.
	 * 
	 * @see EditorDelegate#stopCellEditing
	 */
	public boolean stopCellEditing() {
		return delegate.stopCellEditing();
	}

	/**
	 * Forwards the message from the <code>CellEditor</code> to the
	 * <code>delegate</code>.
	 * 
	 * @see EditorDelegate#cancelCellEditing
	 */
	public void cancelCellEditing() {
		delegate.cancelCellEditing();
	}

	//
	// Implementing the TreeCellEditor Interface
	//

	/** Implements the <code>TreeCellEditor</code> interface. */
	public Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected, boolean expanded,
			boolean leaf, int row) {
		String stringValue = tree.convertValueToText(value, isSelected, expanded, leaf, row, false);

		delegate.setValue(stringValue);
		return editorComponent;
	}

	//
	// Implementing the CellEditor Interface
	//
	/** Implements the <code>TableCellEditor</code> interface. */
	public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
		delegate.setValue(value);
		return editorComponent;
	}

	/**
	 * The protected <code>EditorDelegate</code> class.
	 */
	public class EditorDelegate extends JSEditorDelegateAdapter {
		
		/**
		 * 
		 */
		private static final long serialVersionUID = 1949419889509892785L;
		
		/**
		 * 默认值
		 */
		private T defaultValue;
		
		/**
		 * 编辑控件代理对象
		 * @param defaultValue
		 */
		public EditorDelegate(T defaultValue) {
			this.defaultValue = defaultValue;
		}

		/**
		 * 设置数据的操作
		 */
		@SuppressWarnings("unchecked")
		@Override
		public void setValue(Object value) {
			// 此处实现有点low
			// 原因是我不太明白swing这个table的工作原理，
			// 我猜测，在table第一次加载的时候，本editor就被实例化，然后隐藏起来备用
			// 所有我不在这里设置一下数据，就会窗口加载的时候，一直弹出对话框
			if (!init) {
				label.setText("");
				init = true;
				return;
			}

			this.value = value;
			Collection<T> result = JSTableCollectionDialog.openDialog((Collection<T>)value, defaultValue);
			if (result != null) {
				this.value = result;
				label.setText(this.value.toString());
			}
		}

		/**
		 * 获取单元格数据
		 */
		public Object getCellEditorValue() {
			return this.value;
		}

		/**
		 * Stops editing and returns true to indicate that editing has stopped. This
		 * method calls <code>fireEditingStopped</code>.
		 *
		 * @return true
		 */
		public boolean stopCellEditing() {
			fireEditingStopped();
			return true;
		}

		/**
		 * Cancels editing. This method calls <code>fireEditingCanceled</code>.
		 */
		public void cancelCellEditing() {
			fireEditingCanceled();
		}

		/**
		 * When an action is performed, editing is ended.
		 * 
		 * @param e the action event
		 * @see #stopCellEditing
		 */
		public void actionPerformed(ActionEvent e) {
			JSTableCollectionDialogEditor.this.stopCellEditing();
		}

		/**
		 * When an item's state changes, editing is ended.
		 * 
		 * @param e the action event
		 * @see #stopCellEditing
		 */
		public void itemStateChanged(ItemEvent e) {
			JSTableCollectionDialogEditor.this.stopCellEditing();
		}
	}

}
